/*
Copyright 2019 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sqlparser

import (
	"vitess.io/vitess/go/mysql/datetime"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/vterrors"
)

/*
This is the Vitess AST. This file should only contain pure struct declarations,
or methods used to mark a struct as implementing an interface. All other methods
related to these structs live in ast_funcs.go
*/

// SQLNode defines the interface for all nodes
// generated by the parser.
type SQLNode interface {
	Format(buf *TrackedBuffer)
	FormatFast(buf *TrackedBuffer)
}

// Statements
type (
	// Statement represents a statement.
	Statement interface {
		iStatement()
		SQLNode
	}

	Commented interface {
		SetComments(comments Comments)
		GetParsedComments() *ParsedComments
	}

	// SupportOptimizerHint represents a statement that accepts optimizer hints.
	SupportOptimizerHint interface {
		iSupportOptimizerHint()
		Commented
	}

	OrderAndLimit interface {
		AddOrder(*Order)
		SetLimit(*Limit)
	}

	// SelectStatement any SELECT statement.
	SelectStatement interface {
		Statement
		InsertRows
		OrderAndLimit
		iSelectStatement()
		GetLock() Lock
		SetLock(lock Lock)
		SetInto(into *SelectInto)
		SetWith(with *With)
		MakeDistinct()
		GetColumnCount() int
		GetColumns() SelectExprs
		Commented
		IsDistinct() bool
		GetOrderBy() OrderBy
		SetOrderBy(OrderBy)
		GetLimit() *Limit
	}

	// DDLStatement represents any DDL Statement
	DDLStatement interface {
		iDDLStatement()
		IsFullyParsed() bool
		IsTemporary() bool
		GetTable() TableName
		GetAction() DDLAction
		GetOptLike() *OptLike
		GetIfExists() bool
		GetIfNotExists() bool
		GetIsReplace() bool
		GetTableSpec() *TableSpec
		GetFromTables() TableNames
		GetToTables() TableNames
		AffectedTables() TableNames
		SetTable(qualifier string, name string)
		SetFromTables(tables TableNames)
		SetFullyParsed(fullyParsed bool)
		Commented
		Statement
	}

	// DBDDLStatement represents any DBDDL Statement
	DBDDLStatement interface {
		iDBDDLStatement()
		IsFullyParsed() bool
		GetDatabaseName() string
		SetFullyParsed(bool)
		Statement
	}

	// AlterOption is an interface that represents the various options in ALTER TABLE statements
	AlterOption interface {
		iAlterOption()
		SQLNode
	}

	// Explain is an interface that represents the Explain statements
	Explain interface {
		Statement
		iExplain()
	}

	// AddConstraintDefinition represents a ADD CONSTRAINT alter option
	AddConstraintDefinition struct {
		ConstraintDefinition *ConstraintDefinition
	}

	// AddIndexDefinition represents a ADD INDEX alter option
	AddIndexDefinition struct {
		IndexDefinition *IndexDefinition
	}

	// AddColumns represents a ADD COLUMN alter option
	AddColumns struct {
		Columns []*ColumnDefinition
		First   bool
		After   *ColName
	}

	// AlgorithmValue is the algorithm specified in the alter table command
	AlgorithmValue string

	// AlterColumn is used to add or drop defaults & visibility to columns in alter table command
	AlterColumn struct {
		Column         *ColName
		DropDefault    bool
		DefaultVal     Expr
		DefaultLiteral bool
		Invisible      *bool
	}

	// With contains the lists of common table expression and specifies if it is recursive or not
	With struct {
		CTEs      []*CommonTableExpr
		Recursive bool
	}

	// CommonTableExpr is the structure for supporting common table expressions
	CommonTableExpr struct {
		ID       IdentifierCS
		Columns  Columns
		Subquery SelectStatement
	}
	// ChangeColumn is used to change the column definition, can also rename the column in alter table command
	ChangeColumn struct {
		OldColumn        *ColName
		NewColDefinition *ColumnDefinition
		First            bool
		After            *ColName
	}

	// ModifyColumn is used to change the column definition in alter table command
	ModifyColumn struct {
		NewColDefinition *ColumnDefinition
		First            bool
		After            *ColName
	}

	// RenameColumn is used to change the column definition in alter table command
	RenameColumn struct {
		OldName *ColName
		NewName *ColName
	}

	// AlterCharset is used to set the default or change the character set and collation in alter table command
	AlterCharset struct {
		CharacterSet string
		Collate      string
	}

	// AlterCheck represents the `ALTER CHECK` part in an `ALTER TABLE ALTER CHECK` command.
	AlterCheck struct {
		Name     IdentifierCI
		Enforced bool
	}

	// AlterIndex represents the `ALTER INDEX` part in an `ALTER TABLE ALTER INDEX` command.
	AlterIndex struct {
		Name      IdentifierCI
		Invisible bool
	}

	// KeyState is used to disable or enable the keys in an alter table statement
	KeyState struct {
		Enable bool
	}

	// TablespaceOperation is used to discard or import the tablespace in an alter table statement
	TablespaceOperation struct {
		Import bool
	}

	// DropColumn is used to drop a column in an alter table statement
	DropColumn struct {
		Name *ColName
	}

	// DropKeyType is an enum that represents the type of key being dropped in an alter table statement
	DropKeyType int8

	// DropKey is used to drop a key in an alter table statement
	DropKey struct {
		Type DropKeyType
		Name IdentifierCI
	}

	// Force is used to specify force alter option in an alter table statement
	Force struct{}

	// LockOptionType is an enum for LockOption.Type
	LockOptionType int8

	// LockOption is used to specify the type of lock to use in an alter table statement
	LockOption struct {
		Type LockOptionType
	}

	// OrderByOption clause is used to specify the order by in an alter table statement
	OrderByOption struct {
		Cols Columns
	}

	// RenameTableName clause is used to rename the table in an alter table statement
	RenameTableName struct {
		Table TableName
	}

	// RenameIndex clause is used to rename indexes in an alter table statement
	RenameIndex struct {
		OldName IdentifierCI
		NewName IdentifierCI
	}

	// Validation clause is used to specify whether to use validation or not
	Validation struct {
		With bool
	}

	// Select represents a SELECT statement.
	Select struct {
		Cache            *bool // a reference here so it can be nil
		Distinct         bool
		HighPriority     bool
		StraightJoinHint bool
		SQLSmallResult   bool
		SQLBigResult     bool
		SQLBufferResult  bool
		SQLCalcFoundRows bool
		// The With field needs to come before the FROM clause, so any CTEs have been handled before we analyze it
		With        *With
		From        []TableExpr
		Comments    *ParsedComments
		SelectExprs SelectExprs
		Where       *Where
		GroupBy     *GroupBy
		Having      *Where
		Windows     NamedWindows
		OrderBy     OrderBy
		Limit       *Limit
		Lock        Lock
		Into        *SelectInto
	}

	// SelectInto is a struct that represent the INTO part of a select query
	SelectInto struct {
		Type         SelectIntoType
		FileName     string
		Charset      ColumnCharset
		FormatOption string
		ExportOption string
		Manifest     string
		Overwrite    string
	}

	// SelectIntoType is an enum for SelectInto.Type
	SelectIntoType int8

	// Lock is an enum for the type of lock in the statement
	Lock int8

	// Union represents a UNION/INTERSECT/EXCEPT statement.
	Union struct {
		With     *With
		Left     SelectStatement
		Right    SelectStatement
		Distinct bool
		Type     string
		OrderBy  OrderBy
		Limit    *Limit
		Lock     Lock
		Into     *SelectInto
	}

	// VStream represents a VSTREAM statement.
	VStream struct {
		Comments   *ParsedComments
		SelectExpr SelectExpr
		Table      TableName
		Where      *Where
		Limit      *Limit
	}

	// Stream represents a SELECT statement.
	Stream struct {
		Comments   *ParsedComments
		SelectExpr SelectExpr
		Table      TableName
	}

	// Insert represents an INSERT or REPLACE statement.
	// Per the MySQL docs, http://dev.mysql.com/doc/refman/5.7/en/replace.html
	// Replace is the counterpart to `INSERT IGNORE`, and works exactly like a
	// normal INSERT except if the row exists. In that case it first deletes
	// the row and re-inserts with new values. For that reason we keep it as an Insert struct.
	// Replaces are currently disallowed in sharded schemas because
	// of the implications the deletion part may have on vindexes.
	// If you add fields here, consider adding them to calls to validateUnshardedRoute.
	Insert struct {
		Action   InsertAction
		Comments *ParsedComments
		Ignore   Ignore
		// The Insert as syntax still take TableName.
		// The change is made for semantic analyzer as it takes AliasedTableExpr to provide TableInfo
		Table      *AliasedTableExpr
		Partitions Partitions
		Columns    Columns
		Rows       InsertRows
		RowAlias   *RowAlias
		OnDup      OnDup
	}

	// Ignore represents whether ignore was specified or not
	Ignore bool

	// InsertAction is the action for insert.
	InsertAction int8

	// Update represents an UPDATE statement.
	// If you add fields here, consider adding them to calls to validateUnshardedRoute.
	Update struct {
		With       *With
		Comments   *ParsedComments
		Ignore     Ignore
		TableExprs []TableExpr
		Exprs      UpdateExprs
		Where      *Where
		OrderBy    OrderBy
		Limit      *Limit
	}

	// Delete represents a DELETE statement.
	// If you add fields here, consider adding them to calls to validateUnshardedRoute.
	Delete struct {
		With       *With
		Ignore     Ignore
		Comments   *ParsedComments
		TableExprs []TableExpr
		Targets    TableNames
		Partitions Partitions
		Where      *Where
		OrderBy    OrderBy
		Limit      *Limit
	}

	// Set represents a SET statement.
	Set struct {
		Comments *ParsedComments
		Exprs    SetExprs
	}

	// DropDatabase represents a DROP database statement.
	DropDatabase struct {
		Comments *ParsedComments
		DBName   IdentifierCS
		IfExists bool
	}

	// DatabaseOptionType is an enum for create database options
	DatabaseOptionType int8

	// DatabaseOption is a struct that stores Collation or Character Set value
	DatabaseOption struct {
		Type      DatabaseOptionType
		IsDefault bool
		Value     string
	}

	// CreateDatabase represents a CREATE database statement.
	CreateDatabase struct {
		Comments      *ParsedComments
		DBName        IdentifierCS
		IfNotExists   bool
		CreateOptions []DatabaseOption
		FullyParsed   bool
	}

	// AlterDatabase represents a ALTER database statement.
	AlterDatabase struct {
		Comments            *ParsedComments
		DBName              IdentifierCS
		UpdateDataDirectory bool
		AlterOptions        []DatabaseOption
		FullyParsed         bool
	}

	// Flush represents a FLUSH statement.
	Flush struct {
		IsLocal      bool
		FlushOptions []string
		TableNames   TableNames
		WithLock     bool
		ForExport    bool
	}

	// RenameTablePair represents the name of the original table and what it is going to be set in a RENAME TABLE statement.
	RenameTablePair struct {
		FromTable TableName
		ToTable   TableName
	}

	// RenameTable represents a RENAME TABLE statement.
	RenameTable struct {
		TablePairs []*RenameTablePair
	}

	// TruncateTable represents a TRUNCATE TABLE statement.
	TruncateTable struct {
		Table TableName
	}

	// AlterVschema represents a ALTER VSCHEMA statement.
	AlterVschema struct {
		Action DDLAction
		Table  TableName

		// VindexSpec is set for CreateVindexDDLAction, DropVindexDDLAction, AddColVindexDDLAction, DropColVindexDDLAction.
		VindexSpec *VindexSpec

		// VindexCols is set for AddColVindexDDLAction.
		VindexCols []IdentifierCI

		// AutoIncSpec is set for AddAutoIncDDLAction.
		AutoIncSpec *AutoIncSpec
	}

	// ShowMigrationLogs represents a SHOW VITESS_MIGRATION '<uuid>' LOGS statement
	ShowMigrationLogs struct {
		UUID     string
		Comments *ParsedComments
	}

	// ShowThrottledApps represents a SHOW VITESS_THROTTLED_APPS statement
	ShowThrottledApps struct {
		Comments Comments
	}

	// ShowThrottlerStatus represents a SHOW VITESS_THROTTLED_APPS statement
	ShowThrottlerStatus struct {
		Comments Comments
	}

	// RevertMigration represents a REVERT VITESS_MIGRATION statement
	RevertMigration struct {
		UUID     string
		Comments *ParsedComments
	}

	// AlterMigrationType represents the type of operation in an ALTER VITESS_MIGRATION statement
	AlterMigrationType int8

	// AlterMigration represents a ALTER VITESS_MIGRATION statement
	AlterMigration struct {
		Type   AlterMigrationType
		UUID   string
		Expire string
		Ratio  *Literal
		Shards string
	}

	// AlterTable represents a ALTER TABLE statement.
	AlterTable struct {
		Table           TableName
		AlterOptions    []AlterOption
		PartitionSpec   *PartitionSpec
		PartitionOption *PartitionOption
		Comments        *ParsedComments
		FullyParsed     bool
	}

	// DropTable represents a DROP TABLE statement.
	DropTable struct {
		Temp       bool
		FromTables TableNames
		// The following fields are set if a DDL was fully analyzed.
		IfExists bool
		Comments *ParsedComments
	}

	// DropView represents a DROP VIEW statement.
	DropView struct {
		FromTables TableNames
		IfExists   bool
		Comments   *ParsedComments
	}

	// CreateTable represents a CREATE TABLE statement.
	CreateTable struct {
		Temp        bool
		Table       TableName
		IfNotExists bool
		TableSpec   *TableSpec
		OptLike     *OptLike
		Comments    *ParsedComments
		FullyParsed bool
		Select      SelectStatement
	}

	// CreateView represents a CREATE VIEW query
	CreateView struct {
		ViewName    TableName
		Algorithm   string
		Definer     *Definer
		Security    string
		Columns     Columns
		Select      SelectStatement
		CheckOption string
		IsReplace   bool
		Comments    *ParsedComments
	}

	// AlterView represents a ALTER VIEW query
	AlterView struct {
		ViewName    TableName
		Algorithm   string
		Definer     *Definer
		Security    string
		Columns     Columns
		Select      SelectStatement
		CheckOption string
		Comments    *ParsedComments
	}

	// Definer stores the user for AlterView and CreateView definers
	Definer struct {
		Name    string
		Address string
	}

	// DDLAction is an enum for DDL.Action
	DDLAction int8

	// Load represents a LOAD statement
	Load struct {
	}

	// PurgeBinaryLogs represents a PURGE BINARY LOGS statement
	PurgeBinaryLogs struct {
		To     string
		Before string
	}

	// Show represents a show statement.
	Show struct {
		Internal ShowInternal
	}

	// Use represents a use statement.
	Use struct {
		DBName IdentifierCS
	}

	// TxAccessMode is an enum for Transaction Access Mode
	TxAccessMode int8

	// Begin represents a Begin statement.
	Begin struct {
		TxAccessModes []TxAccessMode
	}

	// Commit represents a Commit statement.
	Commit struct{}

	// Rollback represents a Rollback statement.
	Rollback struct{}

	// SRollback represents a rollback to savepoint statement.
	SRollback struct {
		Name IdentifierCI
	}

	// Savepoint represents a savepoint statement.
	Savepoint struct {
		Name IdentifierCI
	}

	// Release represents a release savepoint statement.
	Release struct {
		Name IdentifierCI
	}

	// CallProc represents a CALL statement
	CallProc struct {
		Name   TableName
		Params Exprs
	}

	// LockType is an enum for Lock Types
	LockType int8

	// TableAndLockType contains table and lock association
	TableAndLockType struct {
		Table TableExpr
		Lock  LockType
	}

	// TableAndLockTypes is a slice of TableAndLockType
	TableAndLockTypes []*TableAndLockType

	// LockTables represents the lock statement
	LockTables struct {
		Tables TableAndLockTypes
	}

	// UnlockTables represents the unlock statement
	UnlockTables struct{}

	// ExplainType is an enum for ExplainStmt.Type
	ExplainType int8

	// ExplainStmt represents an Explain statement
	ExplainStmt struct {
		Type      ExplainType
		Statement Statement
		Comments  *ParsedComments
	}

	// VExplainType is an enum for VExplainStmt.Type
	VExplainType int8

	// VExplainStmt represents an VtExplain statement
	VExplainStmt struct {
		Type      VExplainType
		Statement Statement
		Comments  *ParsedComments
	}

	// ExplainTab represents the Explain table
	ExplainTab struct {
		Table TableName
		Wild  string
	}

	// PrepareStmt represents a Prepare Statement
	// More info available on https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
	PrepareStmt struct {
		Name      IdentifierCI
		Statement Expr
		Comments  *ParsedComments
	}

	// ExecuteStmt represents an Execute Statement
	// More info available on https://dev.mysql.com/doc/refman/8.0/en/execute.html
	ExecuteStmt struct {
		Name      IdentifierCI
		Comments  *ParsedComments
		Arguments []*Variable
	}

	// DeallocateStmt represents a Deallocate Statement
	// More info available on https://dev.mysql.com/doc/refman/8.0/en/deallocate-prepare.html
	DeallocateStmt struct {
		Comments *ParsedComments
		Name     IdentifierCI
	}

	// Analyze represents the Analyze statement.
	Analyze struct {
		IsLocal bool
		Table   TableName
	}

	// OtherAdmin represents a misc statement that relies on ADMIN privileges,
	// such as REPAIR, OPTIMIZE, or TRUNCATE statement.
	// It should be used only as an indicator. It does not contain
	// the full AST for the statement.
	OtherAdmin struct{}

	// CommentOnly represents a query which only has comments
	CommentOnly struct {
		Comments []string
	}

	// KillType is an enum for Kill.Type
	KillType int8

	// Kill represents a kill statement
	Kill struct {
		Type          KillType
		ProcesslistID uint64
	}

	// IndexType is the type of index in a DDL statement
	IndexType int8
)

var _ OrderAndLimit = (*Select)(nil)
var _ OrderAndLimit = (*Update)(nil)
var _ OrderAndLimit = (*Delete)(nil)

func (*Union) iStatement()               {}
func (*Select) iStatement()              {}
func (*Stream) iStatement()              {}
func (*VStream) iStatement()             {}
func (*Insert) iStatement()              {}
func (*Update) iStatement()              {}
func (*Delete) iStatement()              {}
func (*Set) iStatement()                 {}
func (*DropDatabase) iStatement()        {}
func (*Flush) iStatement()               {}
func (*Show) iStatement()                {}
func (*Use) iStatement()                 {}
func (*Begin) iStatement()               {}
func (*Commit) iStatement()              {}
func (*Rollback) iStatement()            {}
func (*SRollback) iStatement()           {}
func (*Savepoint) iStatement()           {}
func (*Release) iStatement()             {}
func (*Analyze) iStatement()             {}
func (*OtherAdmin) iStatement()          {}
func (*CommentOnly) iStatement()         {}
func (*Select) iSelectStatement()        {}
func (*Union) iSelectStatement()         {}
func (*Load) iStatement()                {}
func (*CreateDatabase) iStatement()      {}
func (*AlterDatabase) iStatement()       {}
func (*CreateTable) iStatement()         {}
func (*CreateView) iStatement()          {}
func (*AlterView) iStatement()           {}
func (*LockTables) iStatement()          {}
func (*UnlockTables) iStatement()        {}
func (*AlterTable) iStatement()          {}
func (*AlterVschema) iStatement()        {}
func (*AlterMigration) iStatement()      {}
func (*RevertMigration) iStatement()     {}
func (*ShowMigrationLogs) iStatement()   {}
func (*ShowThrottledApps) iStatement()   {}
func (*ShowThrottlerStatus) iStatement() {}
func (*DropTable) iStatement()           {}
func (*DropView) iStatement()            {}
func (*TruncateTable) iStatement()       {}
func (*RenameTable) iStatement()         {}
func (*CallProc) iStatement()            {}
func (*ExplainStmt) iStatement()         {}
func (*VExplainStmt) iStatement()        {}
func (*ExplainTab) iStatement()          {}
func (*PrepareStmt) iStatement()         {}
func (*ExecuteStmt) iStatement()         {}
func (*DeallocateStmt) iStatement()      {}
func (*PurgeBinaryLogs) iStatement()     {}
func (*Kill) iStatement()                {}

func (*CreateView) iDDLStatement()    {}
func (*AlterView) iDDLStatement()     {}
func (*CreateTable) iDDLStatement()   {}
func (*DropTable) iDDLStatement()     {}
func (*DropView) iDDLStatement()      {}
func (*AlterTable) iDDLStatement()    {}
func (*TruncateTable) iDDLStatement() {}
func (*RenameTable) iDDLStatement()   {}

func (*AddConstraintDefinition) iAlterOption() {}
func (*AddIndexDefinition) iAlterOption()      {}
func (*AddColumns) iAlterOption()              {}
func (AlgorithmValue) iAlterOption()           {}
func (*AlterColumn) iAlterOption()             {}
func (*AlterCheck) iAlterOption()              {}
func (*AlterIndex) iAlterOption()              {}
func (*ChangeColumn) iAlterOption()            {}
func (*ModifyColumn) iAlterOption()            {}
func (*RenameColumn) iAlterOption()            {}
func (*AlterCharset) iAlterOption()            {}
func (*KeyState) iAlterOption()                {}
func (*TablespaceOperation) iAlterOption()     {}
func (*DropColumn) iAlterOption()              {}
func (*DropKey) iAlterOption()                 {}
func (*Force) iAlterOption()                   {}
func (*LockOption) iAlterOption()              {}
func (*OrderByOption) iAlterOption()           {}
func (*RenameTableName) iAlterOption()         {}
func (*RenameIndex) iAlterOption()             {}
func (*Validation) iAlterOption()              {}
func (TableOptions) iAlterOption()             {}

func (*ExplainStmt) iExplain() {}
func (*ExplainTab) iExplain()  {}

func (*Delete) iSupportOptimizerHint()  {}
func (*Insert) iSupportOptimizerHint()  {}
func (*Stream) iSupportOptimizerHint()  {}
func (*Update) iSupportOptimizerHint()  {}
func (*VStream) iSupportOptimizerHint() {}
func (*Select) iSupportOptimizerHint()  {}
func (*Union) iSupportOptimizerHint()   {}

// IsFullyParsed implements the DDLStatement interface
func (*TruncateTable) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (*TruncateTable) SetFullyParsed(bool) {}

// IsFullyParsed implements the DDLStatement interface
func (*RenameTable) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *RenameTable) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *CreateTable) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DDLStatement interface
func (node *CreateTable) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// IsFullyParsed implements the DDLStatement interface
func (node *AlterTable) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DDLStatement interface
func (node *AlterTable) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// IsFullyParsed implements the DDLStatement interface
func (node *CreateView) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *CreateView) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *DropView) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *DropView) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *DropTable) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *DropTable) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DDLStatement interface
func (node *AlterView) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DDLStatement interface
func (node *AlterView) SetFullyParsed(fullyParsed bool) {}

// IsTemporary implements the DDLStatement interface
func (*TruncateTable) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (*RenameTable) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *CreateTable) IsTemporary() bool {
	return node.Temp
}

// IsTemporary implements the DDLStatement interface
func (node *AlterTable) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *CreateView) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *DropView) IsTemporary() bool {
	return false
}

// IsTemporary implements the DDLStatement interface
func (node *DropTable) IsTemporary() bool {
	return node.Temp
}

// IsTemporary implements the DDLStatement interface
func (node *AlterView) IsTemporary() bool {
	return false
}

// GetTable implements the DDLStatement interface
func (node *TruncateTable) GetTable() TableName {
	return node.Table
}

// GetTable implements the DDLStatement interface
func (node *CreateTable) GetTable() TableName {
	return node.Table
}

// GetTable implements the DDLStatement interface
func (node *AlterTable) GetTable() TableName {
	return node.Table
}

// GetTable implements the DDLStatement interface
func (node *CreateView) GetTable() TableName {
	return node.ViewName
}

// GetTable implements the DDLStatement interface
func (node *AlterView) GetTable() TableName {
	return node.ViewName
}

// GetTable implements the DDLStatement interface
func (node *DropView) GetTable() TableName {
	return TableName{}
}

// GetTable implements the DDLStatement interface
func (node *DropTable) GetTable() TableName {
	return TableName{}
}

// GetTable implements the DDLStatement interface
func (node *RenameTable) GetTable() TableName {
	return TableName{}
}

// GetAction implements the DDLStatement interface
func (node *TruncateTable) GetAction() DDLAction {
	return TruncateDDLAction
}

// GetAction implements the DDLStatement interface
func (node *AlterTable) GetAction() DDLAction {
	return AlterDDLAction
}

// GetAction implements the DDLStatement interface
func (node *CreateTable) GetAction() DDLAction {
	return CreateDDLAction
}

// GetAction implements the DDLStatement interface
func (node *CreateView) GetAction() DDLAction {
	return CreateDDLAction
}

// GetAction implements the DDLStatement interface
func (node *AlterView) GetAction() DDLAction {
	return AlterDDLAction
}

// GetAction implements the DDLStatement interface
func (node *RenameTable) GetAction() DDLAction {
	return RenameDDLAction
}

// GetAction implements the DDLStatement interface
func (node *DropTable) GetAction() DDLAction {
	return DropDDLAction
}

// GetAction implements the DDLStatement interface
func (node *DropView) GetAction() DDLAction {
	return DropDDLAction
}

// GetOptLike implements the DDLStatement interface
func (node *CreateTable) GetOptLike() *OptLike {
	return node.OptLike
}

// GetOptLike implements the DDLStatement interface
func (node *TruncateTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *RenameTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *AlterTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *CreateView) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *AlterView) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *DropTable) GetOptLike() *OptLike {
	return nil
}

// GetOptLike implements the DDLStatement interface
func (node *DropView) GetOptLike() *OptLike {
	return nil
}

// GetIfExists implements the DDLStatement interface
func (node *RenameTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *CreateTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *TruncateTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *AlterTable) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *CreateView) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *AlterView) GetIfExists() bool {
	return false
}

// GetIfExists implements the DDLStatement interface
func (node *DropTable) GetIfExists() bool {
	return node.IfExists
}

// GetIfExists implements the DDLStatement interface
func (node *DropView) GetIfExists() bool {
	return node.IfExists
}

// GetIfNotExists implements the DDLStatement interface
func (node *RenameTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *CreateTable) GetIfNotExists() bool {
	return node.IfNotExists
}

// GetIfNotExists implements the DDLStatement interface
func (node *TruncateTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *AlterTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *CreateView) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *AlterView) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *DropTable) GetIfNotExists() bool {
	return false
}

// GetIfNotExists implements the DDLStatement interface
func (node *DropView) GetIfNotExists() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *RenameTable) GetIsReplace() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *CreateTable) GetIsReplace() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *TruncateTable) GetIsReplace() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *AlterTable) GetIsReplace() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *CreateView) GetIsReplace() bool {
	return node.IsReplace
}

// GetIsReplace implements the DDLStatement interface
func (node *AlterView) GetIsReplace() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *DropTable) GetIsReplace() bool {
	return false
}

// GetIsReplace implements the DDLStatement interface
func (node *DropView) GetIsReplace() bool {
	return false
}

// GetTableSpec implements the DDLStatement interface
func (node *CreateTable) GetTableSpec() *TableSpec {
	return node.TableSpec
}

// GetTableSpec implements the DDLStatement interface
func (node *RenameTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *TruncateTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *AlterTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *CreateView) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *AlterView) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *DropTable) GetTableSpec() *TableSpec {
	return nil
}

// GetTableSpec implements the DDLStatement interface
func (node *DropView) GetTableSpec() *TableSpec {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *RenameTable) GetFromTables() TableNames {
	var fromTables TableNames
	for _, pair := range node.TablePairs {
		fromTables = append(fromTables, pair.FromTable)
	}
	return fromTables
}

// GetFromTables implements the DDLStatement interface
func (node *TruncateTable) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *AlterTable) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *CreateTable) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *CreateView) GetFromTables() TableNames {
	return nil
}

// GetFromTables implements the DDLStatement interface
func (node *DropTable) GetFromTables() TableNames {
	return node.FromTables
}

// GetFromTables implements the DDLStatement interface
func (node *DropView) GetFromTables() TableNames {
	return node.FromTables
}

// GetFromTables implements the DDLStatement interface
func (node *AlterView) GetFromTables() TableNames {
	return nil
}

// SetFromTables implements DDLStatement.
func (node *RenameTable) SetFromTables(tables TableNames) {
	if len(node.TablePairs) != len(tables) {
		return
	}
	for i := range node.TablePairs {
		node.TablePairs[i].FromTable = tables[i]
	}
}

// SetFromTables implements DDLStatement.
func (node *TruncateTable) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *AlterTable) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *CreateTable) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *CreateView) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetFromTables implements DDLStatement.
func (node *DropTable) SetFromTables(tables TableNames) {
	node.FromTables = tables
}

// SetFromTables implements DDLStatement.
func (node *DropView) SetFromTables(tables TableNames) {
	node.FromTables = tables
}

// SetFromTables implements DDLStatement.
func (node *AlterView) SetFromTables(tables TableNames) {
	// irrelevant
}

// SetComments implements Commented interface.
func (node *RenameTable) SetComments(comments Comments) {
	// irrelevant
}

// SetComments implements Commented interface.
func (node *TruncateTable) SetComments(comments Comments) {
	// irrelevant
}

// SetComments implements Commented interface.
func (node *AlterTable) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *ExplainStmt) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *VExplainStmt) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *CreateTable) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *CreateView) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *DropTable) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *DropView) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments implements Commented interface.
func (node *AlterView) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments for RevertMigration, does not implement DDLStatement
func (node *RevertMigration) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments for Delete
func (node *Delete) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments for Insert
func (node *Insert) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments for Stream
func (node *Stream) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments for Update
func (node *Update) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// SetComments for VStream
func (node *VStream) SetComments(comments Comments) {
	node.Comments = comments.Parsed()
}

// GetParsedComments implements Commented interface.
func (node *RenameTable) GetParsedComments() *ParsedComments {
	// irrelevant
	return nil
}

// GetParsedComments implements Commented interface.
func (node *TruncateTable) GetParsedComments() *ParsedComments {
	// irrelevant
	return nil
}

// GetParsedComments implements Commented interface.
func (node *AlterTable) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *ExplainStmt) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *VExplainStmt) GetParsedComments() *ParsedComments {
	if node.Comments == nil {
		cmt, ok := node.Statement.(Commented)
		if !ok {
			return nil
		}
		return cmt.GetParsedComments()
	}

	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *CreateTable) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *CreateView) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *DropTable) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *DropView) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Commented interface.
func (node *AlterView) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements SupportOptimizerHint.
func (node *Delete) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Insert.
func (node *Insert) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Stream.
func (node *Stream) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements Update.
func (node *Update) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetParsedComments implements VStream.
func (node *VStream) GetParsedComments() *ParsedComments {
	return node.Comments
}

// GetToTables implements the DDLStatement interface
func (node *RenameTable) GetToTables() TableNames {
	var toTables TableNames
	for _, pair := range node.TablePairs {
		toTables = append(toTables, pair.ToTable)
	}
	return toTables
}

// GetToTables implements the DDLStatement interface
func (node *TruncateTable) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *AlterTable) GetToTables() TableNames {
	for _, option := range node.AlterOptions {
		switch altOption := option.(type) {
		case *RenameTableName:
			return TableNames{altOption.Table}
		}
	}
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *CreateView) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *AlterView) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *CreateTable) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *DropTable) GetToTables() TableNames {
	return nil
}

// GetToTables implements the DDLStatement interface
func (node *DropView) GetToTables() TableNames {
	return nil
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *RenameTable) AffectedTables() TableNames {
	list := make(TableNames, 0, 2*len(node.TablePairs))
	for _, pair := range node.TablePairs {
		list = append(list, pair.FromTable)
		list = append(list, pair.ToTable)
	}
	return list
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *AlterTable) AffectedTables() TableNames {
	affectedTables := TableNames{node.Table}
	for _, option := range node.AlterOptions {
		switch altOption := option.(type) {
		case *RenameTableName:
			affectedTables = append(affectedTables, altOption.Table)
		}
	}
	return affectedTables
}

// AffectedTables implements DDLStatement.
func (node *TruncateTable) AffectedTables() TableNames {
	return TableNames{node.Table}
}

// AffectedTables implements DDLStatement.
func (node *CreateTable) AffectedTables() TableNames {
	return TableNames{node.Table}
}

// AffectedTables implements DDLStatement.
func (node *CreateView) AffectedTables() TableNames {
	return TableNames{node.ViewName}
}

// AffectedTables implements DDLStatement.
func (node *AlterView) AffectedTables() TableNames {
	return TableNames{node.ViewName}
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *DropTable) AffectedTables() TableNames {
	return node.FromTables
}

// AffectedTables returns the list table names affected by the DDLStatement.
func (node *DropView) AffectedTables() TableNames {
	return node.FromTables
}

// SetTable implements DDLStatement.
func (node *TruncateTable) SetTable(qualifier string, name string) {
	node.Table.Qualifier = NewIdentifierCS(qualifier)
	node.Table.Name = NewIdentifierCS(name)
}

// SetTable implements DDLStatement.
func (node *AlterTable) SetTable(qualifier string, name string) {
	node.Table.Qualifier = NewIdentifierCS(qualifier)
	node.Table.Name = NewIdentifierCS(name)
}

// SetTable implements DDLStatement.
func (node *CreateTable) SetTable(qualifier string, name string) {
	node.Table.Qualifier = NewIdentifierCS(qualifier)
	node.Table.Name = NewIdentifierCS(name)
}

// SetTable implements DDLStatement.
func (node *CreateView) SetTable(qualifier string, name string) {
	node.ViewName.Qualifier = NewIdentifierCS(qualifier)
	node.ViewName.Name = NewIdentifierCS(name)
}

// SetTable implements DDLStatement.
func (node *AlterView) SetTable(qualifier string, name string) {
	node.ViewName.Qualifier = NewIdentifierCS(qualifier)
	node.ViewName.Name = NewIdentifierCS(name)
}

// SetTable implements DDLStatement.
func (node *RenameTable) SetTable(qualifier string, name string) {}

// SetTable implements DDLStatement.
func (node *DropTable) SetTable(qualifier string, name string) {}

// SetTable implements DDLStatement.
func (node *DropView) SetTable(qualifier string, name string) {}

func (*DropDatabase) iDBDDLStatement()   {}
func (*CreateDatabase) iDBDDLStatement() {}
func (*AlterDatabase) iDBDDLStatement()  {}

// IsFullyParsed implements the DBDDLStatement interface
func (node *DropDatabase) IsFullyParsed() bool {
	return true
}

// SetFullyParsed implements the DBDDLStatement interface
func (node *DropDatabase) SetFullyParsed(fullyParsed bool) {}

// IsFullyParsed implements the DBDDLStatement interface
func (node *CreateDatabase) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DBDDLStatement interface
func (node *CreateDatabase) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// IsFullyParsed implements the DBDDLStatement interface
func (node *AlterDatabase) IsFullyParsed() bool {
	return node.FullyParsed
}

// SetFullyParsed implements the DBDDLStatement interface
func (node *AlterDatabase) SetFullyParsed(fullyParsed bool) {
	node.FullyParsed = fullyParsed
}

// GetDatabaseName implements the DBDDLStatement interface
func (node *DropDatabase) GetDatabaseName() string {
	return node.DBName.String()
}

// GetDatabaseName implements the DBDDLStatement interface
func (node *CreateDatabase) GetDatabaseName() string {
	return node.DBName.String()
}

// GetDatabaseName implements the DBDDLStatement interface
func (node *AlterDatabase) GetDatabaseName() string {
	return node.DBName.String()
}

type (

	// ShowInternal will represent all the show statement types.
	ShowInternal interface {
		isShowInternal()
		SQLNode
	}

	// ShowCommandType represents the show statement type.
	ShowCommandType int8

	// ShowBasic is of ShowInternal type, holds Simple SHOW queries with a filter.
	ShowBasic struct {
		Command ShowCommandType
		Full    bool
		Tbl     TableName
		DbName  IdentifierCS
		Filter  *ShowFilter
	}

	// ShowTransactionStatus is used to see the status of a distributed transaction in progress.
	ShowTransactionStatus struct {
		Keyspace      string
		TransactionID string
	}

	// ShowCreate is of ShowInternal type, holds SHOW CREATE queries.
	ShowCreate struct {
		Command ShowCommandType
		Op      TableName
	}

	// ShowOther is of ShowInternal type, holds show queries that is not handled specially.
	ShowOther struct {
		Command string
	}
)

func (*ShowBasic) isShowInternal()             {}
func (*ShowCreate) isShowInternal()            {}
func (*ShowOther) isShowInternal()             {}
func (*ShowTransactionStatus) isShowInternal() {}

// InsertRows represents the rows for an INSERT statement.
type InsertRows interface {
	iInsertRows()
	SQLNode
}

func (*Select) iInsertRows() {}
func (*Union) iInsertRows()  {}
func (Values) iInsertRows()  {}

// OptLike works for create table xxx like xxx
type OptLike struct {
	LikeTable TableName
}

// PartitionSpec describe partition actions (for alter statements)
type PartitionSpec struct {
	Action            PartitionSpecAction
	Names             Partitions
	Number            *Literal
	IsAll             bool
	TableName         TableName
	WithoutValidation bool
	Definitions       []*PartitionDefinition
}

// PartitionSpecAction is an enum for PartitionSpec.Action
type PartitionSpecAction int8

// PartitionDefinition describes a very minimal partition definition
type PartitionDefinition struct {
	Name    IdentifierCI
	Options *PartitionDefinitionOptions
}

type PartitionDefinitionOptions struct {
	ValueRange              *PartitionValueRange
	Comment                 *Literal
	Engine                  *PartitionEngine
	DataDirectory           *Literal
	IndexDirectory          *Literal
	MaxRows                 *int
	MinRows                 *int
	TableSpace              string
	SubPartitionDefinitions SubPartitionDefinitions
}

// Subpartition Definition Corresponds to the subpartition_definition option of partition_definition
type SubPartitionDefinition struct {
	Name    IdentifierCI
	Options *SubPartitionDefinitionOptions
}

// This is a list of SubPartitionDefinition
type SubPartitionDefinitions []*SubPartitionDefinition

// Different options/attributes that can be provided to a subpartition_definition.
type SubPartitionDefinitionOptions struct {
	Comment        *Literal
	Engine         *PartitionEngine
	DataDirectory  *Literal
	IndexDirectory *Literal
	MaxRows        *int
	MinRows        *int
	TableSpace     string
}

// PartitionValueRangeType is an enum for PartitionValueRange.Type
type PartitionValueRangeType int8

type PartitionValueRange struct {
	Type     PartitionValueRangeType
	Range    ValTuple
	Maxvalue bool
}

type PartitionEngine struct {
	Storage bool
	Name    string
}

// PartitionByType is an enum storing how we are partitioning a table
type PartitionByType int8

// PartitionOption describes partitioning control (for create table statements)
type PartitionOption struct {
	Type         PartitionByType
	IsLinear     bool
	KeyAlgorithm int
	ColList      Columns
	Expr         Expr
	Partitions   int
	SubPartition *SubPartition
	Definitions  []*PartitionDefinition
}

// SubPartition describes subpartitions control
type SubPartition struct {
	Type          PartitionByType
	IsLinear      bool
	KeyAlgorithm  int
	ColList       Columns
	Expr          Expr
	SubPartitions int
}

// TableOptions specifies a list of table options
type TableOptions []*TableOption

// TableSpec describes the structure of a table from a CREATE TABLE statement
type TableSpec struct {
	Columns         []*ColumnDefinition
	Indexes         []*IndexDefinition
	Constraints     []*ConstraintDefinition
	Options         TableOptions
	PartitionOption *PartitionOption
}

// ColumnDefinition describes a column in a CREATE TABLE statement
type ColumnDefinition struct {
	Name IdentifierCI
	Type *ColumnType
}

// ColumnType represents a sql type in a CREATE TABLE statement
// All optional fields are nil if not specified
type ColumnType struct {
	// The base type string
	Type string

	// Generic field options.
	Options *ColumnTypeOptions

	// Numeric field options
	Length   *int
	Unsigned bool
	Zerofill bool
	Scale    *int

	// Text field options
	Charset ColumnCharset

	// Enum and Set column definition values
	EnumValues []string
}

// ColumnCharset exists because in the type definition it's possible
// to add the binary marker for a character set, so we need to track
// when this happens. We can't at the point of where we parse things
// backfill this with an existing collation. Firstly because we don't
// have access to that during parsing, but more importantly because
// it would generate syntax that is invalid.
//
// Not in all cases where a binary marker is allowed, a collation is
// allowed. See https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html
// specifically under Character Set Conversions.
type ColumnCharset struct {
	Name   string
	Binary bool
}

// ColumnStorage is an enum that defines the type of storage.
type ColumnStorage int

// ColumnFormat is an enum that defines the type of storage.
type ColumnFormat int

// ColumnTypeOptions are generic field options for a column type
type ColumnTypeOptions struct {
	/* We need Null to be *bool to distinguish 3 cases -
	1. When Not Null is specified (Null = false)
	2. When Null is specified (Null = true)
	3. When nothing is specified (Null = nil)
	The complexity arises from the fact that we do not know whether the column will be nullable or not if nothing is specified.
	Therefore we do not know whether the column is nullable or not in case 3.
	*/
	Null           *bool
	Autoincrement  bool
	Default        Expr
	DefaultLiteral bool
	OnUpdate       Expr
	As             Expr
	Comment        *Literal
	Storage        ColumnStorage
	Collate        string
	// Reference stores a foreign key constraint for the given column
	Reference *ReferenceDefinition

	// Key specification
	KeyOpt ColumnKeyOption

	// Stores the tri state of having either VISIBLE, INVISIBLE or nothing specified
	// on the column. In case of nothing, this is nil, when VISIBLE is set it's false
	// and only when INVISIBLE is set does the pointer value return true.
	Invisible *bool

	// Storage format for this specific column. This is NDB specific, but the parser
	// still allows for it and ignores it for other storage engines. So we also should
	// parse it but it's then not used anywhere.
	Format ColumnFormat

	// EngineAttribute is a new attribute not used for anything yet, but accepted
	// since 8.0.23 in the MySQL parser.
	EngineAttribute *Literal

	// SecondaryEngineAttribute is a new attribute not used for anything yet, but accepted
	// since 8.0.23 in the MySQL parser.
	SecondaryEngineAttribute *Literal

	// SRID is an attribute that indiciates the spatial reference system.
	//
	// https://dev.mysql.com/doc/refman/8.0/en/spatial-type-overview.html
	SRID *Literal
}

// IndexDefinition describes an index in a CREATE TABLE statement
type IndexDefinition struct {
	Info    *IndexInfo
	Columns []*IndexColumn
	Options []*IndexOption
}

// IndexInfo describes the name and type of an index in a CREATE TABLE statement
type IndexInfo struct {
	Type           IndexType
	Name           IdentifierCI
	ConstraintName IdentifierCI
}

func (ii *IndexInfo) IsUnique() bool {
	switch ii.Type {
	case IndexTypePrimary, IndexTypeUnique:
		return true
	default:
		return false
	}
}

// VindexSpec defines a vindex for a CREATE VINDEX or DROP VINDEX statement
type VindexSpec struct {
	Name   IdentifierCI
	Type   IdentifierCI
	Params []VindexParam
}

// AutoIncSpec defines and autoincrement value for a ADD AUTO_INCREMENT statement
type AutoIncSpec struct {
	Column   IdentifierCI
	Sequence TableName
}

// VindexParam defines a key/value parameter for a CREATE VINDEX statement
type VindexParam struct {
	Key IdentifierCI
	Val string
}

// ConstraintDefinition describes a constraint in a CREATE TABLE statement
type ConstraintDefinition struct {
	Name    IdentifierCI
	Details ConstraintInfo
}

type (
	// ConstraintInfo details a constraint in a CREATE TABLE statement
	ConstraintInfo interface {
		SQLNode
		iConstraintInfo()
	}

	// ForeignKeyDefinition describes a foreign key in a CREATE TABLE statement
	ForeignKeyDefinition struct {
		Source              Columns
		IndexName           IdentifierCI
		ReferenceDefinition *ReferenceDefinition
	}

	// ReferenceDefinition describes the referenced tables and columns that the foreign key references
	ReferenceDefinition struct {
		ReferencedTable   TableName
		ReferencedColumns Columns
		Match             MatchAction
		OnDelete          ReferenceAction
		OnUpdate          ReferenceAction
	}

	// CheckConstraintDefinition describes a check constraint in a CREATE TABLE statement
	CheckConstraintDefinition struct {
		Expr     Expr
		Enforced bool
	}
)

// ShowFilter is show tables filter
type ShowFilter struct {
	Like   string
	Filter Expr
}

// Comments represents a list of comments.
type Comments []string

func (c Comments) Parsed() *ParsedComments {
	if len(c) == 0 {
		return nil
	}
	return &ParsedComments{comments: c}
}

type ParsedComments struct {
	comments    Comments
	_directives *CommentDirectives
}

// SelectExprs represents SELECT expressions.
type SelectExprs []SelectExpr

type (
	// SelectExpr represents a SELECT expression.
	SelectExpr interface {
		iSelectExpr()
		SQLNode
	}

	// StarExpr defines a '*' or 'table.*' expression.
	StarExpr struct {
		TableName TableName
	}

	// AliasedExpr defines an aliased SELECT expression.
	AliasedExpr struct {
		Expr Expr
		As   IdentifierCI
	}

	// Nextval defines the NEXT VALUE expression.
	Nextval struct {
		Expr Expr
	}
)

func (*StarExpr) iSelectExpr()    {}
func (*AliasedExpr) iSelectExpr() {}
func (*Nextval) iSelectExpr()     {}

// Columns represents an insert column list.
type Columns []IdentifierCI

// Partitions is a type alias for Columns so we can handle printing efficiently
type Partitions Columns

// TableExprs represents a list of table expressions.
type TableExprs []TableExpr

type (
	// TableExpr represents a table expression.
	TableExpr interface {
		iTableExpr()
		SQLNode
	}

	// AliasedTableExpr represents a table expression
	// coupled with an optional alias or index hint.
	// If As is empty, no alias was used.
	AliasedTableExpr struct {
		Expr       SimpleTableExpr
		Partitions Partitions
		As         IdentifierCS
		Hints      IndexHints
		Columns    Columns
	}

	// JoinTableExpr represents a TableExpr that's a JOIN operation.
	JoinTableExpr struct {
		LeftExpr  TableExpr
		Join      JoinType
		RightExpr TableExpr
		Condition *JoinCondition
	}

	// JoinType represents the type of Join for JoinTableExpr
	JoinType int8

	// ParenTableExpr represents a parenthesized list of TableExpr.
	ParenTableExpr struct {
		Exprs TableExprs
	}
)

func (*AliasedTableExpr) iTableExpr() {}
func (*ParenTableExpr) iTableExpr()   {}
func (*JoinTableExpr) iTableExpr()    {}
func (*JSONTableExpr) iTableExpr()    {}

type (
	// SimpleTableExpr represents a simple table expression.
	SimpleTableExpr interface {
		iSimpleTableExpr()
		SQLNode
	}

	// TableName represents a table name.
	// Qualifier, if specified, represents a database or keyspace.
	// TableName is a value struct whose fields are case sensitive.
	// This means two TableName vars can be compared for equality
	// and a TableName can also be used as key in a map.
	TableName struct {
		Name, Qualifier IdentifierCS
		Args            Exprs
	}

	// Subquery represents a subquery used as an value expression.
	Subquery struct {
		Select SelectStatement
	}

	// DerivedTable represents a subquery used as a table expression.
	DerivedTable struct {
		Lateral bool
		Select  SelectStatement
	}
)

func (TableName) iSimpleTableExpr()     {}
func (*DerivedTable) iSimpleTableExpr() {}

// TableNames is a list of TableName.
type TableNames []TableName

// JoinCondition represents the join conditions (either a ON or USING clause)
// of a JoinTableExpr.
type JoinCondition struct {
	On    Expr
	Using Columns
}

// IndexHint represents an index hint.
// More information available on https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
type IndexHint struct {
	Type    IndexHintType
	ForType IndexHintForType
	Indexes []IdentifierCI
}

// IndexHints represents a list of index hints.
type IndexHints []*IndexHint

// IndexHintType is an enum for IndexHint.Type
type IndexHintType int8

// IndexHintForType is an enum for FOR specified in an IndexHint
type IndexHintForType int8

// Where represents a WHERE or HAVING clause.
type Where struct {
	Type WhereType
	Expr Expr
}

// WhereType is an enum for Where.Type
type WhereType int8

// TrimFuncExpr represents a TRIM function
// More information available on https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_trim
type TrimFuncExpr struct {
	TrimFuncType TrimFuncType
	Type         TrimType
	TrimArg      Expr
	StringArg    Expr
}

// TrimFuncType is an enum to get types of TrimFunc.
// TrimFunc stand for one of the following: LTRIM, RTRIM, TRIM
type TrimFuncType int8

// TrimType is an enum to get types of Trim
type TrimType int8

// Types for window functions
type (

	// WindowSpecification represents window_spec
	// More information available here: https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html
	WindowSpecification struct {
		Name            IdentifierCI
		PartitionClause Exprs
		OrderClause     OrderBy
		FrameClause     *FrameClause
	}

	WindowDefinition struct {
		Name       IdentifierCI
		WindowSpec *WindowSpecification
	}

	WindowDefinitions []*WindowDefinition

	NamedWindow struct {
		Windows WindowDefinitions
	}

	NamedWindows []*NamedWindow

	// FrameClause represents frame_clause
	// More information available here: https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html
	FrameClause struct {
		Unit  FrameUnitType
		Start *FramePoint
		End   *FramePoint
	}

	// FramePoint refers to frame_start/frame_end
	// More information available here: https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html
	FramePoint struct {
		Type FramePointType
		Unit IntervalType
		Expr Expr
	}

	// OverClause refers to over_clause
	// More information available here: https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html
	OverClause struct {
		WindowName IdentifierCI
		WindowSpec *WindowSpecification
	}

	// FrameUnitType is an enum to get types of Unit used in FrameClause.
	FrameUnitType int8

	// FrameUnitType is an enum to get types of FramePoint.
	FramePointType int8

	// NullTreatmentClause refers to null_treatment
	// According to SQL Docs:  Some window functions permit a null_treatment clause that specifies how to handle NULL values when calculating results.
	// This clause is optional. It is part of the SQL standard, but the MySQL implementation permits only RESPECT NULLS (which is also the default).
	// This means that NULL values are considered when calculating results. IGNORE NULLS is parsed, but produces an error.
	NullTreatmentClause struct {
		Type NullTreatmentType
	}

	// NullTreatmentType is an enum to get types for NullTreatmentClause
	NullTreatmentType int8

	// FromFirstLastClause refers to from_first_last
	// According to SQL Docs:  from_first_last is part of the SQL standard, but the MySQL implementation permits only FROM FIRST (which is also the default).
	// This means that calculations begin at the first row of the window.
	// FROM LAST is parsed, but produces an error.
	// To obtain the same effect as FROM LAST (begin calculations at the last row of the window), use ORDER BY to sort in reverse order.
	FromFirstLastClause struct {
		Type FromFirstLastType
	}

	// FromFirstLastType is an enum to get types for FromFirstLastClause
	FromFirstLastType int8
)

// *********** Expressions
type (
	// Expr represents an expression.
	Expr interface {
		IsExpr()
		SQLNode
	}

	Callable interface {
		iCallable()
		Expr
	}

	// AndExpr represents an AND expression.
	AndExpr struct {
		Left, Right Expr
	}

	// OrExpr represents an OR expression.
	OrExpr struct {
		Left, Right Expr
	}

	// XorExpr represents an XOR expression.
	XorExpr struct {
		Left, Right Expr
	}

	// NotExpr represents a NOT expression.
	NotExpr struct {
		Expr Expr
	}

	// ComparisonExpr represents a two-value comparison expression.
	ComparisonExpr struct {
		Operator    ComparisonExprOperator
		Modifier    ComparisonModifier
		Left, Right Expr
		Escape      Expr
	}

	// ComparisonExprOperator is an enum for ComparisonExpr.Operator
	ComparisonExprOperator int8

	// ComparisonModifier is an enum for ComparisonExpr.Modifier
	ComparisonModifier int8

	// BetweenExpr represents a BETWEEN or a NOT BETWEEN expression.
	BetweenExpr struct {
		IsBetween bool
		Left      Expr
		From, To  Expr
	}

	// RangeCondOperator is an enum for RangeCond.Operator
	RangeCondOperator int8

	// IsExpr represents an IS ... or an IS NOT ... expression.
	IsExpr struct {
		Left  Expr
		Right IsExprOperator
	}

	// IsExprOperator is an enum for IsExpr.Operator
	IsExprOperator int8

	// ExistsExpr represents an EXISTS expression.
	ExistsExpr struct {
		Subquery *Subquery
	}

	// AssignmentExpr represents an expression of type @value := x.
	AssignmentExpr struct {
		Left, Right Expr
	}

	// Literal represents a fixed value.
	Literal struct {
		Type ValType
		Val  string
	}

	// Argument represents bindvariable expression
	Argument struct {
		Name        string
		Type        sqltypes.Type
		Size, Scale int32
	}

	// NullVal represents a NULL value.
	NullVal struct{}

	// BoolVal is true or false.
	BoolVal bool

	// ColName represents a column name.
	ColName struct {
		Name      IdentifierCI
		Qualifier TableName
	}

	// Scope is an enum for scope of query
	Scope int8

	Variable struct {
		Scope Scope
		Name  IdentifierCI
	}

	// ColTuple represents a list of column values.
	// It can be ValTuple, Subquery, ListArg.
	ColTuple interface {
		iColTuple()
		Expr
	}

	// ListArg represents a named list argument.
	ListArg string

	// ValTuple represents a tuple of actual values.
	ValTuple Exprs

	// BinaryExpr represents a binary value expression.
	BinaryExpr struct {
		Operator    BinaryExprOperator
		Left, Right Expr
	}

	// BinaryExprOperator is an enum for BinaryExpr.Operator
	BinaryExprOperator int8

	// UnaryExpr represents a unary value expression.
	UnaryExpr struct {
		Operator UnaryExprOperator
		Expr     Expr
	}

	// UnaryExprOperator is an enum for UnaryExpr.Operator
	UnaryExprOperator int8

	// IntroducerExpr represents a unary value expression.
	IntroducerExpr struct {
		CharacterSet string
		Expr         Expr
	}

	// TimestampDiffExpr represents the function and arguments for TIMESTAMPDIFF functions.
	TimestampDiffExpr struct {
		Expr1 Expr
		Expr2 Expr
		Unit  IntervalType
	}

	// ExtractFuncExpr represents the function and arguments for EXTRACT(YEAR FROM '2019-07-02') type functions.
	ExtractFuncExpr struct {
		IntervalType IntervalType
		Expr         Expr
	}

	// CollateExpr represents dynamic collate operator.
	CollateExpr struct {
		Expr      Expr
		Collation string
	}

	// WeightStringFuncExpr represents the function and arguments for WEIGHT_STRING('string' AS [CHAR|BINARY](n))
	WeightStringFuncExpr struct {
		Expr Expr
		As   *ConvertType
	}

	// FuncExpr represents a function call.
	FuncExpr struct {
		Qualifier IdentifierCS
		Name      IdentifierCI
		Exprs     Exprs
	}

	// ValuesFuncExpr represents a function call.
	ValuesFuncExpr struct {
		Name *ColName
	}

	// SubstrExpr represents a calls to
	// - SubstrExpr(expression, expression, expression)
	// - SubstrExpr(expression, expression)
	// - SubstrExpr(expression FROM expression)
	// - SubstrExpr(expression FROM expression FOR expression)
	SubstrExpr struct {
		Name Expr
		From Expr
		To   Expr
	}

	// CastExpr represents a call to CAST(expr AS type)
	// This is separate from CONVERT(expr, type) since there are
	// places such as in CREATE TABLE statements where they
	// are treated differently.
	CastExpr struct {
		Expr  Expr
		Type  *ConvertType
		Array bool
	}

	// ConvertExpr represents a call to CONVERT(expr, type)
	ConvertExpr struct {
		Expr Expr
		Type *ConvertType
	}

	// ConvertUsingExpr represents a call to CONVERT(expr USING charset).
	ConvertUsingExpr struct {
		Expr Expr
		Type string
	}

	// MatchExpr represents a call to the MATCH function
	MatchExpr struct {
		Columns []*ColName
		Expr    Expr
		Option  MatchExprOption
	}

	// MatchExprOption is an enum for MatchExpr.Option
	MatchExprOption int8

	// CaseExpr represents a CASE expression.
	CaseExpr struct {
		Expr  Expr
		Whens []*When
		Else  Expr
	}

	// InsertExpr represents an INSERT expression
	InsertExpr struct {
		Str    Expr
		Pos    Expr
		Len    Expr
		NewStr Expr
	}

	// IntervalFuncExpr represents an INTERVAL function expression
	IntervalFuncExpr struct {
		Expr  Expr
		Exprs Exprs
	}

	// LocateExpr represents a LOCATE function expression
	LocateExpr struct {
		SubStr Expr
		Str    Expr
		Pos    Expr
	}

	// CharExpr represents a CHAR function expression
	CharExpr struct {
		Exprs   Exprs
		Charset string
	}

	// Default represents a DEFAULT expression.
	Default struct {
		ColName string
	}

	// When represents a WHEN sub-expression.
	When struct {
		Cond Expr
		Val  Expr
	}

	// CurTimeFuncExpr represents the function and arguments for CURRENT DATE/TIME functions
	// supported functions are documented in the grammar
	CurTimeFuncExpr struct {
		Name IdentifierCI
		Fsp  int // fractional seconds precision, integer from 0 to 6 or an Argument
	}

	// JSONPrettyExpr represents the function and argument for JSON_PRETTY()
	// https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-pretty
	JSONPrettyExpr struct {
		JSONVal Expr
	}

	// JSONStorageFreeExpr represents the function and argument for JSON_STORAGE_FREE()
	// https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-storage-free
	JSONStorageFreeExpr struct {
		JSONVal Expr
	}

	// JSONStorageSizeExpr represents the function and argument for JSON_STORAGE_SIZE()
	// https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-storage-size
	JSONStorageSizeExpr struct {
		JSONVal Expr
	}

	// Offset is an AST type that is used during planning and never produced by the parser
	// it is the column offset from the incoming result stream
	Offset struct {
		V        int
		Original Expr
	}

	// JSONArrayExpr represents JSON_ARRAY()
	// More information on https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-array
	JSONArrayExpr struct {
		Params Exprs
	}

	// JSONObjectExpr represents JSON_OBJECT()
	// More information on https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-object
	JSONObjectExpr struct {
		Params []*JSONObjectParam
	}

	// JSONObjectParam defines a key/value parameter for a JSON_OBJECT expression
	JSONObjectParam struct {
		Key   Expr
		Value Expr
	}

	// JSONQuoteExpr represents JSON_QUOTE()
	// More information https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-quote
	JSONQuoteExpr struct {
		StringArg Expr
	}

	// JSONTableExpr describes the components of JSON_TABLE()
	// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table
	JSONTableExpr struct {
		Expr    Expr
		Alias   IdentifierCS
		Filter  Expr
		Columns []*JtColumnDefinition
	}

	// JSONArrayAgg is an aggregation expression that creates a JSON Array.
	// For more information, visit https://dev.mysql.com/doc/refman/8.4/en/aggregate-functions.html#function_json-arrayagg
	JSONArrayAgg struct {
		Expr       Expr
		OverClause *OverClause
	}

	// JSONObjectAgg is an aggregation expression that creates a JSON Object.
	// For more information, visit https://dev.mysql.com/doc/refman/8.4/en/aggregate-functions.html#function_json-objectagg
	JSONObjectAgg struct {
		Key        Expr
		Value      Expr
		OverClause *OverClause
	}

	// JtOnResponseType describes the type of column: default, error or null
	JtOnResponseType int

	// JtColumnDefinition represents the structure of column definition in JSON_TABLE
	JtColumnDefinition struct {
		JtOrdinal    *JtOrdinalColDef
		JtPath       *JtPathColDef
		JtNestedPath *JtNestedPathColDef
	}

	// JtOrdinalColDef is a type of column definition similar to using AUTO_INCREMENT with a column
	JtOrdinalColDef struct {
		Name IdentifierCI
	}

	// JtPathColDef is a type of column definition specifying the path in JSON structure to extract values
	JtPathColDef struct {
		Name            IdentifierCI
		Type            *ColumnType
		JtColExists     bool
		Path            Expr
		EmptyOnResponse *JtOnResponse
		ErrorOnResponse *JtOnResponse
	}

	// JtNestedPathColDef is type of column definition with nested column definitions
	JtNestedPathColDef struct {
		Path    Expr
		Columns []*JtColumnDefinition
	}

	// JtOnResponse specifies for a column the JtOnResponseType along with the expression for default and error
	JtOnResponse struct {
		ResponseType JtOnResponseType
		Expr         Expr
	}

	// JSONContainsExpr represents the function and arguments for JSON_CONTAINS()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains
	JSONContainsExpr struct {
		Target    Expr
		Candidate Expr
		PathList  []Expr
	}

	// JSONContainsPathExpr represents the function and arguments for JSON_CONTAINS_PATH()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains-path
	JSONContainsPathExpr struct {
		JSONDoc  Expr
		OneOrAll Expr
		PathList []Expr
	}

	// JSONContainsPathType is an enum to get types of Trim
	JSONContainsPathType int8

	// JSONExtractExpr represents the function and arguments for JSON_EXTRACT()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-extract
	JSONExtractExpr struct {
		JSONDoc  Expr
		PathList []Expr
	}

	// JSONKeysExpr represents the function and arguments for JSON_KEYS()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-keys
	JSONKeysExpr struct {
		JSONDoc Expr
		Path    Expr
	}

	// JSONOverlapsExpr represents the function and arguments for JSON_OVERLAPS()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-overlaps
	JSONOverlapsExpr struct {
		JSONDoc1 Expr
		JSONDoc2 Expr
	}

	// JSONSearchExpr represents the function and arguments for JSON_SEARCH()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-search
	JSONSearchExpr struct {
		JSONDoc    Expr
		OneOrAll   Expr
		SearchStr  Expr
		EscapeChar Expr
		PathList   []Expr
	}

	// JSONValueExpr represents the function and arguments for JSON_VALUE()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-value
	JSONValueExpr struct {
		JSONDoc         Expr
		Path            Expr
		ReturningType   *ConvertType
		EmptyOnResponse *JtOnResponse
		ErrorOnResponse *JtOnResponse
	}

	// MemberOf represents the function and arguments for MEMBER OF()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#operator_member-of
	MemberOfExpr struct {
		Value   Expr
		JSONArr Expr
	}

	// JSONSchemaValidFuncExpr represents the structure of JSON_SCHEMA_VALID()
	// More information available on https://dev.mysql.com/doc/refman/8.0/en/json-validation-functions.html#function_json-schema-valid
	JSONSchemaValidFuncExpr struct {
		Schema   Expr
		Document Expr
	}

	// JSONSchemaValidationReportFuncExpr represents the structure of JSON_SCHEMA_VALIDATION_REPORT()
	// More information available on https://dev.mysql.com/doc/refman/8.0/en/json-validation-functions.html#function_json-schema-validation-report
	JSONSchemaValidationReportFuncExpr struct {
		Schema   Expr
		Document Expr
	}

	// JSONAttributesExpr represents the argument and function for functions returning JSON value attributes
	// More information available on https://dev.mysql.com/doc/refman/8.0/en/json-attribute-functions.html
	JSONAttributesExpr struct {
		Type    JSONAttributeType
		JSONDoc Expr
		Path    Expr
	}

	// JSONAttributeType is an enum to get types of TrimFunc.
	// TrimFunc stand for one of the following: JSON_DEPTH JSON_TYPE JSON_VALID ENUM
	JSONAttributeType int8

	JSONValueModifierExpr struct {
		Type    JSONValueModifierType
		JSONDoc Expr
		Params  []*JSONObjectParam
	}

	// JSONValueModifierType is an enum to get types of TrimFunc.
	// TrimFunc stand for one of the following: JSON_DEPTH JSON_TYPE JSON_VALID ENUM
	JSONValueModifierType int8

	// JSONValueMergeExpr represents the json value modifier functions which merges documents.
	// Functions falling under this class: JSON_MERGE, JSON_MERGE_PATCH, JSON_MERGE_PRESERVE
	JSONValueMergeExpr struct {
		Type        JSONValueMergeType
		JSONDoc     Expr
		JSONDocList Exprs
	}

	// JSONValueModifierType is an enum to get types of TrimFunc.
	// TrimFunc stand for one of the following: JSON_DEPTH JSON_TYPE JSON_VALID ENUM
	JSONValueMergeType int8

	// JSONRemoveExpr represents the JSON_REMOVE()
	// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-remove
	JSONRemoveExpr struct {
		JSONDoc  Expr
		PathList Exprs
	}

	// JSONRemoveExpr represents the JSON_UNQUOTE()
	// For more information, postVisit https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-unquote
	JSONUnquoteExpr struct {
		JSONValue Expr
	}

	// PointExpr represents POINT(x,y) expression
	PointExpr struct {
		XCordinate Expr
		YCordinate Expr
	}

	// LineString represents LineString(POINT(x,y), POINT(x,y), ..) expression
	LineStringExpr struct {
		PointParams Exprs
	}

	// PolygonExpr represents Polygon(LineString(POINT(x,y), POINT(x,y), ..)) expressions
	PolygonExpr struct {
		LinestringParams Exprs
	}

	// MultiPoint represents a geometry collection for points
	MultiPointExpr struct {
		PointParams Exprs
	}

	// MultiPoint represents a geometry collection for linestrings
	MultiLinestringExpr struct {
		LinestringParams Exprs
	}

	// MultiPolygon represents a geometry collection for polygons
	MultiPolygonExpr struct {
		PolygonParams Exprs
	}

	// GeomFromWktType is an enum to get the types of wkt functions with possible values: GeometryFromText GeometryCollectionFromText PointFromText LineStringFromText PolygonFromText MultiPointFromText MultiPolygonFromText MultiLinestringFromText
	GeomFromWktType int8

	GeomFromTextExpr struct {
		Type         GeomFromWktType
		WktText      Expr
		Srid         Expr
		AxisOrderOpt Expr
	}

	// GeomFromWkbType is an enum to get the types of wkb functions with possible values: GeometryFromWKB GeometryCollectionFromWKB PointFromWKB LineStringFromWKB PolygonFromWKB MultiPointFromWKB MultiPolygonFromWKB MultiLinestringFromWKB
	GeomFromWkbType int8

	GeomFromWKBExpr struct {
		Type         GeomFromWkbType
		WkbBlob      Expr
		Srid         Expr
		AxisOrderOpt Expr
	}

	// GeomFormatType is an enum to get the types of geom format functions with possible values: BinaryFormat TextFormat
	GeomFormatType int8

	GeomFormatExpr struct {
		FormatType   GeomFormatType
		Geom         Expr
		AxisOrderOpt Expr
	}

	// GeomPropertyType is an enum to get the types of geom property functions with possible values: Dimension Envelope IsSimple IsEmpty GeometryType
	GeomPropertyType int8

	GeomPropertyFuncExpr struct {
		Property GeomPropertyType
		Geom     Expr
	}

	// PointPropertyType is an that enumerates the kind of point property functions: XCordinate YCordinate Latitude Longitude
	PointPropertyType int8

	PointPropertyFuncExpr struct {
		Property   PointPropertyType
		Point      Expr
		ValueToSet Expr
	}

	// LinestrPropType is an enum that enumerates the kind of line string property functions: EndPoint IsClosed Length NumPoints PointN StartPoint
	LinestrPropType int8

	LinestrPropertyFuncExpr struct {
		Property       LinestrPropType
		Linestring     Expr
		PropertyDefArg Expr
	}

	// PolygonPropType is an enum that enumerates the kind of polygon property functions: Area Centroid ExteriorRing InteriorRingN NumInteriorRing
	PolygonPropType int8

	PolygonPropertyFuncExpr struct {
		Property       PolygonPropType
		Polygon        Expr
		PropertyDefArg Expr
	}

	// GeomCollPropType is an enumthat enumerates the kind of geom coll property functions with possible values: GeometryN NumGeometries
	GeomCollPropType int8

	GeomCollPropertyFuncExpr struct {
		Property       GeomCollPropType
		GeomColl       Expr
		PropertyDefArg Expr
	}

	GeoHashFromLatLongExpr struct {
		Latitude  Expr
		Longitude Expr
		MaxLength Expr
	}

	GeoHashFromPointExpr struct {
		Point     Expr
		MaxLength Expr
	}

	// GeomFromHashType is an enum that determines what kind geom being retireived from hash
	GeomFromHashType int8

	GeomFromGeoHashExpr struct {
		GeomType GeomFromHashType
		GeoHash  Expr
		SridOpt  Expr
	}

	GeoJSONFromGeomExpr struct {
		Geom             Expr
		MaxDecimalDigits Expr
		Bitmask          Expr
	}

	GeomFromGeoJSONExpr struct {
		GeoJSON             Expr
		HigherDimHandlerOpt Expr // This value determine how the higher dimensions are handled while converting json to geometry
		Srid                Expr
	}

	AggrFunc interface {
		Expr
		GetArg() Expr
		GetArgs() Exprs
		SetArg(expr Expr)
		SetArgs(exprs Exprs) error
		// AggrName returns the lower case string representing this aggregation function
		AggrName() string
	}

	DistinctableAggr interface {
		IsDistinct() bool
		SetDistinct(bool)
	}

	Count struct {
		Args       Exprs
		Distinct   bool
		OverClause *OverClause
	}

	CountStar struct {
		_ bool
		// TL;DR; This makes sure that reference equality checks works as expected
		//
		// You're correct that this might seem a bit strange at first glance.
		// It's a quirk of Go's handling of empty structs. In Go, two instances of an empty struct are considered
		// identical, which can be problematic when using these as keys in maps.
		// They would be treated as the same key and potentially lead to incorrect map behavior.
		//
		// Here's a brief example:
		//
		// ```golang
		// func TestWeirdGo(t *testing.T) {
		// 	type CountStar struct{}
		//
		// 	cs1 := &CountStar{}
		// 	cs2 := &CountStar{}
		//  if cs1 == cs2 {
		// 	  panic("what the what!?")
		//  }
		// }
		// ```
		//
		// In the above code, cs1 and cs2, despite being distinct variables, would be treated as the same object.
		//
		// The solution we employed was to add a dummy field `_ bool` to the otherwise empty struct `CountStar`.
		// This ensures that each instance of `CountStar` is treated as a separate object,
		// even in the context of out semantic state which uses these objects as map keys.
		OverClause *OverClause
	}

	Avg struct {
		Arg        Expr
		Distinct   bool
		OverClause *OverClause
	}

	Max struct {
		Arg        Expr
		Distinct   bool
		OverClause *OverClause
	}

	Min struct {
		Arg        Expr
		Distinct   bool
		OverClause *OverClause
	}

	Sum struct {
		Arg        Expr
		Distinct   bool
		OverClause *OverClause
	}

	BitAnd struct {
		Arg        Expr
		OverClause *OverClause
	}

	BitOr struct {
		Arg        Expr
		OverClause *OverClause
	}

	BitXor struct {
		Arg        Expr
		OverClause *OverClause
	}

	Std struct {
		Arg        Expr
		OverClause *OverClause
	}

	StdDev struct {
		Arg        Expr
		OverClause *OverClause
	}

	StdPop struct {
		Arg        Expr
		OverClause *OverClause
	}

	StdSamp struct {
		Arg        Expr
		OverClause *OverClause
	}

	VarPop struct {
		Arg        Expr
		OverClause *OverClause
	}

	VarSamp struct {
		Arg        Expr
		OverClause *OverClause
	}

	Variance struct {
		Arg        Expr
		OverClause *OverClause
	}

	// GroupConcatExpr represents a call to GROUP_CONCAT
	GroupConcatExpr struct {
		Distinct  bool
		Exprs     Exprs
		OrderBy   OrderBy
		Separator string
		Limit     *Limit
	}

	// AnyValue is an aggregation function in Vitess, even if the MySQL manual explicitly says it's not
	// It's just simpler to treat it as one
	// see https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_any-value
	AnyValue struct {
		Arg Expr
	}

	// RegexpInstrExpr represents REGEXP_INSTR()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-instr
	RegexpInstrExpr struct {
		Expr         Expr
		Pattern      Expr
		Position     Expr
		Occurrence   Expr
		ReturnOption Expr
		MatchType    Expr
	}

	// RegexpLikeExpr represents REGEXP_LIKE()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-like
	RegexpLikeExpr struct {
		Expr      Expr
		Pattern   Expr
		MatchType Expr
	}

	// RegexpReplaceExpr represents REGEXP_REPLACE()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-replace
	RegexpReplaceExpr struct {
		Expr       Expr
		Pattern    Expr
		Repl       Expr
		Occurrence Expr
		Position   Expr
		MatchType  Expr
	}

	// RegexpSubstrExpr represents REGEXP_SUBSTR()
	// For more information, see https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-substr
	RegexpSubstrExpr struct {
		Expr       Expr
		Pattern    Expr
		Occurrence Expr
		Position   Expr
		MatchType  Expr
	}

	IntervalType = datetime.IntervalType

	// IntervalDateExpr represents ADDDATE(), DATE_ADD()
	IntervalDateExpr struct {
		Syntax   IntervalExprSyntax
		Date     Expr
		Interval Expr
		Unit     IntervalType
	}

	// ArgumentLessWindowExpr stands for the following window_functions: CUME_DIST, DENSE_RANK, PERCENT_RANK, RANK, ROW_NUMBER
	// These functions do not take any argument.
	ArgumentLessWindowExpr struct {
		Type       ArgumentLessWindowExprType
		OverClause *OverClause
	}

	// ArgumentLessWindowExprType is an enum to get types of ArgumentLessWindowExpr.
	ArgumentLessWindowExprType int8

	// FirstOrLastValueExpr stands for the following window_functions: FIRST_VALUE, LAST_VALUE
	FirstOrLastValueExpr struct {
		Type                FirstOrLastValueExprType
		Expr                Expr
		NullTreatmentClause *NullTreatmentClause
		OverClause          *OverClause
	}

	// FirstOrLastValueExprType is an enum to get types of FirstOrLastValueExpr.
	FirstOrLastValueExprType int8

	// NtileExpr stands for the NTILE()
	NtileExpr struct {
		N          Expr
		OverClause *OverClause
	}

	// NTHValueExpr stands for the NTH_VALUE()
	NTHValueExpr struct {
		Expr                Expr
		N                   Expr
		OverClause          *OverClause
		FromFirstLastClause *FromFirstLastClause
		NullTreatmentClause *NullTreatmentClause
	}

	// LagLeadExpr stand for the following: LAG, LEAD
	LagLeadExpr struct {
		Type                LagLeadExprType
		Expr                Expr
		N                   Expr
		Default             Expr
		OverClause          *OverClause
		NullTreatmentClause *NullTreatmentClause
	}

	// LagLeadExprType is an enum to get types of LagLeadExpr.
	LagLeadExprType int8

	// ExtractValueExpr stands for EXTRACTVALUE() XML function
	// Extract a value from an XML string using XPath notation
	// For more details, postVisit https://dev.mysql.com/doc/refman/8.0/en/xml-functions.html#function_extractvalue
	ExtractValueExpr struct {
		Fragment  Expr
		XPathExpr Expr
	}

	// UpdateXMLExpr stands for UpdateXML() XML function
	// Return replaced XML fragment
	// For more details, postVisit https://dev.mysql.com/doc/refman/8.0/en/xml-functions.html#function_updatexml
	UpdateXMLExpr struct {
		Target    Expr
		XPathExpr Expr
		NewXML    Expr
	}

	// LockingFuncType is an enum that get types of LockingFunc
	LockingFuncType int8

	// LockingFunc represents the advisory lock functions.
	LockingFunc struct {
		Type    LockingFuncType
		Name    Expr
		Timeout Expr
	}

	// PerformanceSchemaType is an enum that get types of LockingFunc
	PerformanceSchemaType int8

	// PerformanceSchemaFuncExpr stands for Performance Schema Functions
	// Argument has different meanings for different types
	// For FORMAT_BYTES, it means count
	// For FORMAT_PICO_TIME, it means time_val
	// For PS_THREAD_ID it means connection_id
	// For more details, postVisit https://dev.mysql.com/doc/refman/8.0/en/performance-schema-functions.html
	PerformanceSchemaFuncExpr struct {
		Type     PerformanceSchemaType
		Argument Expr
	}

	// GTIDType is an enum that get types of GTIDFunc
	GTIDType int8

	// GTIDFuncExpr stands for GTID Functions
	// Set1 Acts as gtid_set for WAIT_FOR_EXECUTED_GTID_SET() and WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS()
	// For more details, postVisit https://dev.mysql.com/doc/refman/8.0/en/gtid-functions.html
	GTIDFuncExpr struct {
		Type    GTIDType
		Set1    Expr
		Set2    Expr
		Timeout Expr
		Channel Expr
	}
)

// IsExpr ensures that only expressions nodes can be assigned to a Expr
func (*AndExpr) IsExpr()                            {}
func (*OrExpr) IsExpr()                             {}
func (*XorExpr) IsExpr()                            {}
func (*NotExpr) IsExpr()                            {}
func (*ComparisonExpr) IsExpr()                     {}
func (*BetweenExpr) IsExpr()                        {}
func (*IsExpr) IsExpr()                             {}
func (*ExistsExpr) IsExpr()                         {}
func (*AssignmentExpr) IsExpr()                     {}
func (*Literal) IsExpr()                            {}
func (*Argument) IsExpr()                           {}
func (*NullVal) IsExpr()                            {}
func (BoolVal) IsExpr()                             {}
func (*ColName) IsExpr()                            {}
func (ValTuple) IsExpr()                            {}
func (*Subquery) IsExpr()                           {}
func (ListArg) IsExpr()                             {}
func (*BinaryExpr) IsExpr()                         {}
func (*UnaryExpr) IsExpr()                          {}
func (*IntroducerExpr) IsExpr()                     {}
func (*CollateExpr) IsExpr()                        {}
func (*FuncExpr) IsExpr()                           {}
func (*TimestampDiffExpr) IsExpr()                  {}
func (*ExtractFuncExpr) IsExpr()                    {}
func (*WeightStringFuncExpr) IsExpr()               {}
func (*CurTimeFuncExpr) IsExpr()                    {}
func (*CaseExpr) IsExpr()                           {}
func (*ValuesFuncExpr) IsExpr()                     {}
func (*CastExpr) IsExpr()                           {}
func (*ConvertExpr) IsExpr()                        {}
func (*SubstrExpr) IsExpr()                         {}
func (*InsertExpr) IsExpr()                         {}
func (*IntervalFuncExpr) IsExpr()                   {}
func (*LocateExpr) IsExpr()                         {}
func (*CharExpr) IsExpr()                           {}
func (*ConvertUsingExpr) IsExpr()                   {}
func (*MatchExpr) IsExpr()                          {}
func (*Default) IsExpr()                            {}
func (*TrimFuncExpr) IsExpr()                       {}
func (*JSONSchemaValidFuncExpr) IsExpr()            {}
func (*JSONSchemaValidationReportFuncExpr) IsExpr() {}
func (*Offset) IsExpr()                             {}
func (*JSONPrettyExpr) IsExpr()                     {}
func (*JSONStorageFreeExpr) IsExpr()                {}
func (*JSONStorageSizeExpr) IsExpr()                {}
func (*JSONContainsExpr) IsExpr()                   {}
func (*JSONContainsPathExpr) IsExpr()               {}
func (*JSONExtractExpr) IsExpr()                    {}
func (*JSONKeysExpr) IsExpr()                       {}
func (*JSONOverlapsExpr) IsExpr()                   {}
func (*JSONSearchExpr) IsExpr()                     {}
func (*JSONValueExpr) IsExpr()                      {}
func (*JSONArrayExpr) IsExpr()                      {}
func (*JSONArrayAgg) IsExpr()                       {}
func (*JSONObjectExpr) IsExpr()                     {}
func (*JSONObjectAgg) IsExpr()                      {}
func (*JSONQuoteExpr) IsExpr()                      {}
func (*JSONAttributesExpr) IsExpr()                 {}
func (*JSONValueModifierExpr) IsExpr()              {}
func (*JSONValueMergeExpr) IsExpr()                 {}
func (*JSONRemoveExpr) IsExpr()                     {}
func (*JSONUnquoteExpr) IsExpr()                    {}
func (*MemberOfExpr) IsExpr()                       {}
func (*RegexpInstrExpr) IsExpr()                    {}
func (*RegexpLikeExpr) IsExpr()                     {}
func (*RegexpReplaceExpr) IsExpr()                  {}
func (*RegexpSubstrExpr) IsExpr()                   {}
func (*IntervalDateExpr) IsExpr()                   {}
func (*ArgumentLessWindowExpr) IsExpr()             {}
func (*FirstOrLastValueExpr) IsExpr()               {}
func (*NtileExpr) IsExpr()                          {}
func (*NTHValueExpr) IsExpr()                       {}
func (*LagLeadExpr) IsExpr()                        {}
func (*NamedWindow) IsExpr()                        {}
func (*ExtractValueExpr) IsExpr()                   {}
func (*UpdateXMLExpr) IsExpr()                      {}
func (*LockingFunc) IsExpr()                        {}
func (*PerformanceSchemaFuncExpr) IsExpr()          {}
func (*GTIDFuncExpr) IsExpr()                       {}
func (*Sum) IsExpr()                                {}
func (*Min) IsExpr()                                {}
func (*Max) IsExpr()                                {}
func (*Avg) IsExpr()                                {}
func (*CountStar) IsExpr()                          {}
func (*Count) IsExpr()                              {}
func (*GroupConcatExpr) IsExpr()                    {}
func (*AnyValue) IsExpr()                           {}
func (*BitAnd) IsExpr()                             {}
func (*BitOr) IsExpr()                              {}
func (*BitXor) IsExpr()                             {}
func (*Std) IsExpr()                                {}
func (*StdDev) IsExpr()                             {}
func (*StdPop) IsExpr()                             {}
func (*StdSamp) IsExpr()                            {}
func (*VarPop) IsExpr()                             {}
func (*VarSamp) IsExpr()                            {}
func (*Variance) IsExpr()                           {}
func (*Variable) IsExpr()                           {}
func (*PointExpr) IsExpr()                          {}
func (*LineStringExpr) IsExpr()                     {}
func (*PolygonExpr) IsExpr()                        {}
func (*MultiPolygonExpr) IsExpr()                   {}
func (*MultiPointExpr) IsExpr()                     {}
func (*MultiLinestringExpr) IsExpr()                {}
func (*GeomFromTextExpr) IsExpr()                   {}
func (*GeomFromWKBExpr) IsExpr()                    {}
func (*GeomFormatExpr) IsExpr()                     {}
func (*GeomPropertyFuncExpr) IsExpr()               {}
func (*PointPropertyFuncExpr) IsExpr()              {}
func (*LinestrPropertyFuncExpr) IsExpr()            {}
func (*PolygonPropertyFuncExpr) IsExpr()            {}
func (*GeomCollPropertyFuncExpr) IsExpr()           {}
func (*GeoHashFromLatLongExpr) IsExpr()             {}
func (*GeoHashFromPointExpr) IsExpr()               {}
func (*GeomFromGeoHashExpr) IsExpr()                {}
func (*GeoJSONFromGeomExpr) IsExpr()                {}
func (*GeomFromGeoJSONExpr) IsExpr()                {}

// iCallable marks all expressions that represent function calls
func (*FuncExpr) iCallable()                           {}
func (*TimestampDiffExpr) iCallable()                  {}
func (*ExtractFuncExpr) iCallable()                    {}
func (*WeightStringFuncExpr) iCallable()               {}
func (*CurTimeFuncExpr) iCallable()                    {}
func (*ValuesFuncExpr) iCallable()                     {}
func (*ConvertExpr) iCallable()                        {}
func (*TrimFuncExpr) iCallable()                       {}
func (*SubstrExpr) iCallable()                         {}
func (*InsertExpr) iCallable()                         {}
func (*IntervalFuncExpr) iCallable()                   {}
func (*LocateExpr) iCallable()                         {}
func (*CharExpr) iCallable()                           {}
func (*ConvertUsingExpr) iCallable()                   {}
func (*MatchExpr) iCallable()                          {}
func (*GroupConcatExpr) iCallable()                    {}
func (*AnyValue) iCallable()                           {}
func (*JSONSchemaValidFuncExpr) iCallable()            {}
func (*JSONSchemaValidationReportFuncExpr) iCallable() {}
func (*JSONPrettyExpr) iCallable()                     {}
func (*JSONStorageFreeExpr) iCallable()                {}
func (*JSONStorageSizeExpr) iCallable()                {}
func (*JSONArrayExpr) iCallable()                      {}
func (*JSONObjectExpr) iCallable()                     {}
func (*JSONQuoteExpr) iCallable()                      {}
func (*JSONContainsExpr) iCallable()                   {}
func (*JSONContainsPathExpr) iCallable()               {}
func (*JSONExtractExpr) iCallable()                    {}
func (*JSONKeysExpr) iCallable()                       {}
func (*JSONValueExpr) iCallable()                      {}
func (*JSONSearchExpr) iCallable()                     {}
func (*JSONOverlapsExpr) iCallable()                   {}
func (*JSONAttributesExpr) iCallable()                 {}
func (*JSONValueModifierExpr) iCallable()              {}
func (*JSONValueMergeExpr) iCallable()                 {}
func (*JSONRemoveExpr) iCallable()                     {}
func (*JSONUnquoteExpr) iCallable()                    {}
func (*MemberOfExpr) iCallable()                       {}
func (*RegexpInstrExpr) iCallable()                    {}
func (*RegexpLikeExpr) iCallable()                     {}
func (*RegexpReplaceExpr) iCallable()                  {}
func (*RegexpSubstrExpr) iCallable()                   {}
func (*IntervalDateExpr) iCallable()                   {}
func (*ArgumentLessWindowExpr) iCallable()             {}
func (*FirstOrLastValueExpr) iCallable()               {}
func (*NtileExpr) iCallable()                          {}
func (*NTHValueExpr) iCallable()                       {}
func (*LagLeadExpr) iCallable()                        {}
func (*NamedWindow) iCallable()                        {}
func (*ExtractValueExpr) iCallable()                   {}
func (*UpdateXMLExpr) iCallable()                      {}
func (*PerformanceSchemaFuncExpr) iCallable()          {}
func (*GTIDFuncExpr) iCallable()                       {}
func (*PointExpr) iCallable()                          {}
func (*LineStringExpr) iCallable()                     {}
func (*PolygonExpr) iCallable()                        {}
func (*MultiPolygonExpr) iCallable()                   {}
func (*MultiPointExpr) iCallable()                     {}
func (*MultiLinestringExpr) iCallable()                {}
func (*GeomFromTextExpr) iCallable()                   {}
func (*GeomFromWKBExpr) iCallable()                    {}
func (*GeomFormatExpr) iCallable()                     {}
func (*GeomPropertyFuncExpr) iCallable()               {}
func (*PointPropertyFuncExpr) iCallable()              {}
func (*LinestrPropertyFuncExpr) iCallable()            {}
func (*PolygonPropertyFuncExpr) iCallable()            {}
func (*GeomCollPropertyFuncExpr) iCallable()           {}
func (*GeoHashFromLatLongExpr) iCallable()             {}
func (*GeoHashFromPointExpr) iCallable()               {}
func (*GeomFromGeoHashExpr) iCallable()                {}
func (*GeoJSONFromGeomExpr) iCallable()                {}
func (*GeomFromGeoJSONExpr) iCallable()                {}

func (*Sum) iCallable()       {}
func (*Min) iCallable()       {}
func (*Max) iCallable()       {}
func (*Avg) iCallable()       {}
func (*CountStar) iCallable() {}
func (*Count) iCallable()     {}

func (sum *Sum) GetArg() Expr                   { return sum.Arg }
func (min *Min) GetArg() Expr                   { return min.Arg }
func (max *Max) GetArg() Expr                   { return max.Arg }
func (avg *Avg) GetArg() Expr                   { return avg.Arg }
func (*CountStar) GetArg() Expr                 { return nil }
func (count *Count) GetArg() Expr               { return count.Args[0] }
func (grpConcat *GroupConcatExpr) GetArg() Expr { return grpConcat.Exprs[0] }
func (bAnd *BitAnd) GetArg() Expr               { return bAnd.Arg }
func (bOr *BitOr) GetArg() Expr                 { return bOr.Arg }
func (bXor *BitXor) GetArg() Expr               { return bXor.Arg }
func (std *Std) GetArg() Expr                   { return std.Arg }
func (stdD *StdDev) GetArg() Expr               { return stdD.Arg }
func (stdP *StdPop) GetArg() Expr               { return stdP.Arg }
func (stdS *StdSamp) GetArg() Expr              { return stdS.Arg }
func (varP *VarPop) GetArg() Expr               { return varP.Arg }
func (varS *VarSamp) GetArg() Expr              { return varS.Arg }
func (variance *Variance) GetArg() Expr         { return variance.Arg }
func (av *AnyValue) GetArg() Expr               { return av.Arg }
func (jaa *JSONArrayAgg) GetArg() Expr          { return jaa.Expr }
func (joa *JSONObjectAgg) GetArg() Expr         { return joa.Key }

func (sum *Sum) GetArgs() Exprs                   { return Exprs{sum.Arg} }
func (min *Min) GetArgs() Exprs                   { return Exprs{min.Arg} }
func (max *Max) GetArgs() Exprs                   { return Exprs{max.Arg} }
func (avg *Avg) GetArgs() Exprs                   { return Exprs{avg.Arg} }
func (*CountStar) GetArgs() Exprs                 { return nil }
func (count *Count) GetArgs() Exprs               { return count.Args }
func (grpConcat *GroupConcatExpr) GetArgs() Exprs { return grpConcat.Exprs }
func (bAnd *BitAnd) GetArgs() Exprs               { return Exprs{bAnd.Arg} }
func (bOr *BitOr) GetArgs() Exprs                 { return Exprs{bOr.Arg} }
func (bXor *BitXor) GetArgs() Exprs               { return Exprs{bXor.Arg} }
func (std *Std) GetArgs() Exprs                   { return Exprs{std.Arg} }
func (stdD *StdDev) GetArgs() Exprs               { return Exprs{stdD.Arg} }
func (stdP *StdPop) GetArgs() Exprs               { return Exprs{stdP.Arg} }
func (stdS *StdSamp) GetArgs() Exprs              { return Exprs{stdS.Arg} }
func (varP *VarPop) GetArgs() Exprs               { return Exprs{varP.Arg} }
func (varS *VarSamp) GetArgs() Exprs              { return Exprs{varS.Arg} }
func (variance *Variance) GetArgs() Exprs         { return Exprs{variance.Arg} }
func (av *AnyValue) GetArgs() Exprs               { return Exprs{av.Arg} }
func (jaa *JSONArrayAgg) GetArgs() Exprs          { return Exprs{jaa.Expr} }
func (joa *JSONObjectAgg) GetArgs() Exprs         { return Exprs{joa.Key, joa.Value} }

func (min *Min) SetArg(expr Expr)                   { min.Arg = expr }
func (sum *Sum) SetArg(expr Expr)                   { sum.Arg = expr }
func (max *Max) SetArg(expr Expr)                   { max.Arg = expr }
func (avg *Avg) SetArg(expr Expr)                   { avg.Arg = expr }
func (*CountStar) SetArg(expr Expr)                 {}
func (count *Count) SetArg(expr Expr)               { count.Args = Exprs{expr} }
func (grpConcat *GroupConcatExpr) SetArg(expr Expr) { grpConcat.Exprs = Exprs{expr} }
func (bAnd *BitAnd) SetArg(expr Expr)               { bAnd.Arg = expr }
func (bOr *BitOr) SetArg(expr Expr)                 { bOr.Arg = expr }
func (bXor *BitXor) SetArg(expr Expr)               { bXor.Arg = expr }
func (std *Std) SetArg(expr Expr)                   { std.Arg = expr }
func (stdD *StdDev) SetArg(expr Expr)               { stdD.Arg = expr }
func (stdP *StdPop) SetArg(expr Expr)               { stdP.Arg = expr }
func (stdS *StdSamp) SetArg(expr Expr)              { stdS.Arg = expr }
func (varP *VarPop) SetArg(expr Expr)               { varP.Arg = expr }
func (varS *VarSamp) SetArg(expr Expr)              { varS.Arg = expr }
func (variance *Variance) SetArg(expr Expr)         { variance.Arg = expr }
func (av *AnyValue) SetArg(expr Expr)               { av.Arg = expr }
func (jaa *JSONArrayAgg) SetArg(expr Expr)          { jaa.Expr = expr }
func (joa *JSONObjectAgg) SetArg(expr Expr)         { joa.Key = expr }

func (min *Min) SetArgs(exprs Exprs) error           { return setFuncArgs(min, exprs, "MIN") }
func (sum *Sum) SetArgs(exprs Exprs) error           { return setFuncArgs(sum, exprs, "SUM") }
func (max *Max) SetArgs(exprs Exprs) error           { return setFuncArgs(max, exprs, "MAX") }
func (avg *Avg) SetArgs(exprs Exprs) error           { return setFuncArgs(avg, exprs, "AVG") }
func (*CountStar) SetArgs(Exprs) error               { return nil }
func (bAnd *BitAnd) SetArgs(exprs Exprs) error       { return setFuncArgs(bAnd, exprs, "BIT_AND") }
func (bOr *BitOr) SetArgs(exprs Exprs) error         { return setFuncArgs(bOr, exprs, "BIT_OR") }
func (bXor *BitXor) SetArgs(exprs Exprs) error       { return setFuncArgs(bXor, exprs, "BIT_XOR") }
func (std *Std) SetArgs(exprs Exprs) error           { return setFuncArgs(std, exprs, "STD") }
func (stdD *StdDev) SetArgs(exprs Exprs) error       { return setFuncArgs(stdD, exprs, "STDDEV") }
func (stdP *StdPop) SetArgs(exprs Exprs) error       { return setFuncArgs(stdP, exprs, "STDDEV_POP") }
func (stdS *StdSamp) SetArgs(exprs Exprs) error      { return setFuncArgs(stdS, exprs, "STDDEV_SAMP") }
func (varP *VarPop) SetArgs(exprs Exprs) error       { return setFuncArgs(varP, exprs, "VAR_POP") }
func (varS *VarSamp) SetArgs(exprs Exprs) error      { return setFuncArgs(varS, exprs, "VAR_SAMP") }
func (variance *Variance) SetArgs(exprs Exprs) error { return setFuncArgs(variance, exprs, "VARIANCE") }
func (av *AnyValue) SetArgs(exprs Exprs) error       { return setFuncArgs(av, exprs, "ANY_VALUE") }
func (jaa *JSONArrayAgg) SetArgs(exprs Exprs) error  { return setFuncArgs(jaa, exprs, "JSON_ARRAYARG") }
func (joa *JSONObjectAgg) SetArgs(exprs Exprs) error {
	if len(exprs) != 2 {
		return vterrors.VT13001("JSONObjectAgg takes in 2 expressions")
	}
	joa.Key = exprs[0]
	joa.Value = exprs[1]
	return nil
}

func (count *Count) SetArgs(exprs Exprs) error {
	count.Args = exprs
	return nil
}
func (grpConcat *GroupConcatExpr) SetArgs(exprs Exprs) error {
	grpConcat.Exprs = exprs
	return nil
}

func (sum *Sum) IsDistinct() bool                   { return sum.Distinct }
func (min *Min) IsDistinct() bool                   { return min.Distinct }
func (max *Max) IsDistinct() bool                   { return max.Distinct }
func (avg *Avg) IsDistinct() bool                   { return avg.Distinct }
func (count *Count) IsDistinct() bool               { return count.Distinct }
func (grpConcat *GroupConcatExpr) IsDistinct() bool { return grpConcat.Distinct }

func (sum *Sum) SetDistinct(distinct bool)                   { sum.Distinct = distinct }
func (min *Min) SetDistinct(distinct bool)                   { min.Distinct = distinct }
func (max *Max) SetDistinct(distinct bool)                   { max.Distinct = distinct }
func (avg *Avg) SetDistinct(distinct bool)                   { avg.Distinct = distinct }
func (count *Count) SetDistinct(distinct bool)               { count.Distinct = distinct }
func (grpConcat *GroupConcatExpr) SetDistinct(distinct bool) { grpConcat.Distinct = distinct }

func (*Sum) AggrName() string             { return "sum" }
func (*Min) AggrName() string             { return "min" }
func (*Max) AggrName() string             { return "max" }
func (*Avg) AggrName() string             { return "avg" }
func (*CountStar) AggrName() string       { return "count" }
func (*Count) AggrName() string           { return "count" }
func (*GroupConcatExpr) AggrName() string { return "group_concat" }
func (*BitAnd) AggrName() string          { return "bit_and" }
func (*BitOr) AggrName() string           { return "bit_or" }
func (*BitXor) AggrName() string          { return "bit_xor" }
func (*Std) AggrName() string             { return "std" }
func (*StdDev) AggrName() string          { return "stddev" }
func (*StdPop) AggrName() string          { return "stddev_pop" }
func (*StdSamp) AggrName() string         { return "stddev_samp" }
func (*VarPop) AggrName() string          { return "var_pop" }
func (*VarSamp) AggrName() string         { return "var_samp" }
func (*Variance) AggrName() string        { return "variance" }
func (*AnyValue) AggrName() string        { return "any_value" }
func (*JSONArrayAgg) AggrName() string    { return "json_arrayagg" }
func (*JSONObjectAgg) AggrName() string   { return "json_objectagg" }

// Exprs represents a list of value expressions.
// It's not a valid expression because it's not parenthesized.
type Exprs []Expr

func (ValTuple) iColTuple()  {}
func (*Subquery) iColTuple() {}
func (ListArg) iColTuple()   {}

// ConvertType represents the type in call to CONVERT(expr, type)
type ConvertType struct {
	Type    string
	Length  *int
	Scale   *int
	Charset ColumnCharset
}

// GroupBy represents a GROUP BY clause.
type GroupBy struct {
	Exprs      []Expr
	WithRollup bool
}

// OrderBy represents an ORDER By clause.
type OrderBy []*Order

// Order represents an ordering expression.
type Order struct {
	Expr      Expr
	Direction OrderDirection
}

// OrderDirection is an enum for the direction in which to order - asc or desc.
type OrderDirection int8

// Limit represents a LIMIT clause.
type Limit struct {
	Offset, Rowcount Expr
}

// Values represents a VALUES clause.
type Values []ValTuple

// UpdateExprs represents a list of update expressions.
type UpdateExprs []*UpdateExpr

// UpdateExpr represents an update expression.
type UpdateExpr struct {
	Name *ColName
	Expr Expr
}

// SetExprs represents a list of set expressions.
type SetExprs []*SetExpr

// SetExpr represents a set expression.
type SetExpr struct {
	Var  *Variable
	Expr Expr
}

// OnDup represents an ON DUPLICATE KEY clause.
type OnDup UpdateExprs

type RowAlias struct {
	TableName IdentifierCS
	Columns   Columns
}

// IdentifierCI is a case insensitive SQL identifier. It will be escaped with
// backquotes if necessary.
type IdentifierCI struct {
	// This artifact prevents this struct from being compared
	// with itself. It consumes no space as long as it's not the
	// last field in the struct.
	_            [0]struct{ _ []byte }
	val, lowered string
}

// IdentifierCS is a case sensitive SQL identifier. It will be escaped with
// backquotes if necessary.
type IdentifierCS struct {
	v string
}
